Library UNISIM;
use UNISIM.vcomponents.all;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity OutputBlock is
  Port( Device0data : inout std_logic_vector(15 downto 0);
        Device0i2cClk : inout std_logic;
        Device0i2cData : inout std_logic;
        
        Device1data : inout std_logic_vector(15 downto 0);
        Device1i2cClk : inout std_logic;
        Device1i2cData : inout std_logic;
        
        MasterData : inout std_logic_vector(15 downto 0);
        MasterI2CClk : inout std_logic;
        MasterI2CData : inout std_logic);
end OutputBlock;

architecture behav of OutputBlock is

  component I2Cslave_debug is
    Generic (register_data_width : natural;
             register_id_width : natural);
    Port ( Data : inout  STD_LOGIC;
           Clk : in  STD_LOGIC;
           FPGAClk : in std_logic;
           register_id : out std_logic_vector(register_id_width-1 downto 0);
           Data_to_send : in std_logic_vector(register_data_width-1 downto 0);
           Data_out : out std_logic_vector(7 downto 0));
  end component;
  
  signal regID, Data : std_logic_vector(7 downto 0);
  signal i2cData,i2cClk,FPGAClk : std_logic:='0';
  
  component I2Cwatcher is
  Port(I2CData : in std_logic;
       I2CClk : in std_logic;
       Direction : out std_logic);
  end component;
  
  type dataOut is array(1 downto 0) of std_logic_vector(18 downto 0); 
  --[0]I2CClk; [1]I2CData; [2]Direction; [3:18]IMG_Data;
  --[0]Out; [1]In
  signal dev0,dev1,master : dataOut;
  signal current_dir,m_dir,d0_dir,d1_dir : std_logic;
  signal reg : std_logic_vector(7 downto 0):=X"00";
  
  begin
    
    m_dir<=not current_dir;
    I2C: I2Cslave_debug
      generic map(8,8)
      port map(i2cData,i2cClk,FPGAClk,regID,Data,reg);

    DirCtrl: I2Cwatcher port map(i2cData,i2cClk,current_dir);
      
    Direction: process(current_dir,reg,master,dev0,dev1)
    begin
        case reg is
          when X"01" =>null;
            d0_dir<=current_dir;
            d1_dir<='1';
            if current_dir = '1' then
              i2cData<=dev0(0)(1);
              i2cClk<=dev0(0)(0);
            else
              dev0(1)(1)<=i2cData;
              dev0(1)(0)<=i2cClk;
            end if;
          when X"02" =>null;
            d0_dir<='1';
            d1_dir<=current_dir;
            if current_dir = '1' then
              i2cData<=dev1(0)(1);
              i2cClk<=dev1(0)(0);
            else
              dev1(1)(1)<=i2cData;
              dev1(1)(0)<=i2cClk;
            end if;
          when others =>null;
            d0_dir<='1';
            d1_dir<='1';
            
            i2cData<=master(1)(1);
            i2cClk<=master(1)(0);
        end case;
    end process;
           
    --Generate Device0Data
    Device0_data: for i in 0 to 18 generate
        --IOBUF: Single-ended Bi-directional Buffer All devices
   	    --Xilinx HDL Libraries Guide version 8.1i
	      IOBUF_inst0 : IOBUF 
		    generic map (
     			  DRIVE => 12, 
			    IBUF_DELAY_VALUE => "0", 	-- Specify the amount of added input delay for buffer, "0"-"16" (Spartan-3E only)
     			  IFD_DELAY_VALUE => "AUTO", -- Specify the amount of added delay for input register, "AUTO", "0"-"8" (Spartan-3E only)
     			  IOSTANDARD => "DEFAULT",
			    SLEW => "SLOW") 
		    port map (
			    O => dev0(0)(i), 		-- Buffer output
			    IO => Device0data(i), 	-- Buffer inout port (connect directly to top-level port)
			    I => dev0(1)(i), 		-- Buffer input
			    T => m_dir		-- 3-state enable input
		    ); 
	      --End of IOBUF_inst instantiation
	    end generate;
	  
	      
	  --Generate Device1Data
	  Device1_data: for i in 0 to 17 generate
        --IOBUF: Single-ended Bi-directional Buffer All devices
   	    --Xilinx HDL Libraries Guide version 8.1i
	      IOBUF_inst1 : IOBUF 
		    generic map (
     			  DRIVE => 12, 
			    IBUF_DELAY_VALUE => "0", 	-- Specify the amount of added input delay for buffer, "0"-"16" (Spartan-3E only)
     			  IFD_DELAY_VALUE => "AUTO", -- Specify the amount of added delay for input register, "AUTO", "0"-"8" (Spartan-3E only)
     			  IOSTANDARD => "DEFAULT",
			    SLEW => "SLOW") 
		    port map (
			    O => dev1(0)(i), 		-- Buffer output
			    IO => Device1data(i), 	-- Buffer inout port (connect directly to top-level port)
			    I => dev1(1)(i), 		-- Buffer input
			    T => d0_dir		-- 3-state enable input
		    ); 
	      --End of IOBUF_inst instantiation
	    end generate;
	    
	  --Generate MasterData
	    Master_data: for i in 0 to 17 generate
        --IOBUF: Single-ended Bi-directional Buffer All devices
   	    --Xilinx HDL Libraries Guide version 8.1i
	      IOBUF_inst2 : IOBUF 
		    generic map (
     			  DRIVE => 12, 
			    IBUF_DELAY_VALUE => "0", 	-- Specify the amount of added input delay for buffer, "0"-"16" (Spartan-3E only)
     			  IFD_DELAY_VALUE => "AUTO", -- Specify the amount of added delay for input register, "AUTO", "0"-"8" (Spartan-3E only)
     			  IOSTANDARD => "DEFAULT",
			    SLEW => "SLOW") 
		    port map (
			    O => master(0)(i), 		-- Buffer output
			    IO => MasterData(i), 	-- Buffer inout port (connect directly to top-level port)
			    I => Master(1)(i), 		-- Buffer input
			    T => d1_dir		-- 3-state enable input
		    ); 
	      --End of IOBUF_inst instantiation
	    end generate;
    
end behav;